#include "raytracer.hpp"

Raytracer::Raytracer(Scene* _scene,Grid* _grid,const Vector& _position,const Vector& _up,const unsigned short _depth) : scene(_scene), grid(_grid), position(_position), up(_up), depth(_depth) 
{}

Raytracer::~Raytracer(void) { 
	delete scene;
	delete grid;
}

int Raytracer::trace(const Ray& _ray,Vector& _point) const {
	return scene->nearest_object(_point,_ray);
}

void Raytracer::render(void) const {
	unsigned short height = grid->get_height();
	unsigned short width = grid->get_width();

	Vector d(0.0f,0.0f,grid->get_position().z);
	Ray ray(position,d);
	Vector point;
	
	Color color;
	/*const double gradeX = grade->get_width().x;
	const double gradeY = grade->get_height().y;*/
	double teta1;
	double teta2;
	//double px;
	const double incx = 2.0/width;
	const double incy = 2.0/height;
	int x;
	#ifdef _OPENMP
		#pragma omp parallel for default(shared) firstprivate(ray) private(x,teta1,teta2,color,point) shared(tga) num_threads(2) 
	#endif
	for(x = 0;x < width;x++) {
		double px = incx*x-1.0;
		teta1 = (M_PI/4.0)*px;
		const double cos_teta1 = cos(teta1);
		double py = -1.0;
		for(int y =0;y < height;y++) {
			teta2 = (M_PI/4.0)*py;
			const double cos_teta2 = cos(teta2);
			
			ray.set_direction(Vector(cos_teta2*sin(teta1),
						sin(teta2),
						-cos_teta2*cos_teta1
					).normalize());

			/* trace() returns the point where is a intersection
			 * obj returns the index to identify the object */
			int obj = trace(ray,point); 
			
			if (obj != -1) {	 /* -1 means no intersection */
				color = illumination.calculate_color_rec(obj,ray,point,scene,depth);
			}
			#ifdef _OPENMP
				#pragma omp critical (set_pixel)
			#endif
			{
				output->set_pixel(x,y,color);
				color.set(scene->get_background());
			}
			py += incy;
		}
	}
}

void Raytracer::set_scene(Scene* _scene) { scene = _scene; }

void Raytracer::set_grid(Grid* _grid) { grid = _grid; }

void Raytracer::set_output(Output* _output) { output = _output; }

void Raytracer::set_position(const Vector& _position) { position = _position; }

void Raytracer::set_up(const Vector& _up) { up = _up; }

Scene* Raytracer::get_scene(void) const { return scene; }

Grid* Raytracer::get_grid(void) const { return grid; }

Output* Raytracer::get_output(void) const { return output; }

Vector Raytracer::get_position(void) const { return position; }

Vector Raytracer::getUp(void) const { return up; }



